package com.ruoyi.business.workshop.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ruoyi.business.communication.domain.SlotStatus;
import com.ruoyi.business.communication.listener.DeviceStatusListener;
import com.ruoyi.business.workshop.domain.WorkshopArea;
import com.ruoyi.business.workshop.domain.WorkshopFactory;
import com.ruoyi.business.workshop.domain.WorkshopSection;
import com.ruoyi.business.workshop.domain.WorkshopSlotInfo;
import com.ruoyi.business.workshop.domain.WorkshopPositionInfo;
import com.ruoyi.business.workshop.dto.WorkshopSlotDTO;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.business.device.domain.Device;

import jakarta.annotation.PostConstruct;

/**
 * 车间管理服务
 * 提供车间架构展示和槽位状态查询功能
 * 
 * @author ruoyi
 */
@Service
public class WorkshopManagementService implements DeviceStatusListener{

    private static final Logger log = LoggerFactory.getLogger(WorkshopManagementService.class);


    public static final String WORKSHOP_SECTION_STATUS_KEY = "WorkshopSectionSlotStatus[SN]:";
    /** Redis缓存Key常量 */
    private static final String WORKSHOP_SLOT_STATUS_KEY = "WorkshopSlotStatus";

    @Autowired
    private RedisCache redisCache;
    
    /** 静态车间架构数据 */
    private List<WorkshopArea> areas = new ArrayList<>();
    
    

    /**
     * 初始化静态车间架构数据
     */
    @PostConstruct
    private void buildStaticData() {
        // 一工区
        WorkshopFactory f1 = new WorkshopFactory("一厂房", Arrays.asList(
            new WorkshopSection("11段", 1001, 1075, 75, 4),
            new WorkshopSection("12段", 1076, 1151, 76, 4)
        ));
        WorkshopFactory f2 = new WorkshopFactory("二厂房", Arrays.asList(
            new WorkshopSection("21段", 2001, 2075, 75, 4),
            new WorkshopSection("22段", 2076, 2151, 76, 4)
        ));
        WorkshopArea a1 = new WorkshopArea("一工区", Arrays.asList(f1, f2));

        // 二工区
        WorkshopFactory f3 = new WorkshopFactory("三厂房", Arrays.asList(
            new WorkshopSection("31段", 3001, 3075, 75, 4),
            new WorkshopSection("32段", 3076, 3151, 76, 4)
        ));
        WorkshopFactory f4 = new WorkshopFactory("四厂房", Arrays.asList(
            new WorkshopSection("41段", 4001, 4075, 75, 4),
            new WorkshopSection("42段", 4076, 4151, 76, 4)
        ));
        WorkshopArea a2 = new WorkshopArea("二工区", Arrays.asList(f3, f4));

        // 三工区
        WorkshopFactory f5 = new WorkshopFactory("五厂房", Arrays.asList(
            new WorkshopSection("51段", 5001, 5077, 77, 6),
            new WorkshopSection("52段", 5078, 5154, 77, 6)
        ));
        WorkshopFactory f6 = new WorkshopFactory("六厂房", Arrays.asList(
            new WorkshopSection("61段", 6001, 6077, 77, 6),
            new WorkshopSection("62段", 6078, 6154, 77, 6)
        ));
        WorkshopArea a3 = new WorkshopArea("三工区", Arrays.asList(f5, f6));

        this.areas.add(a1);
        this.areas.add(a2);
        this.areas.add(a3);

        this.cacheAllSlotsToRedis();
    }

    /**
     * 获取车间工区列表（不包含状态）
     * 
     * @return 车间工区列表
     */
    public List<WorkshopArea> listAreas() {
        return areas;
    }

    /**
     * 根据工区名称获取厂房列表
     * 
     * @param areaName 工区名称
     * @return 厂房列表
     */
    public List<WorkshopFactory> getFactoriesByAreaName(String areaName) {
        for (WorkshopArea area : areas) {
            if (areaName.equals(area.getAreaName())) {
                return area.getFactories();
            }
        }
        return new ArrayList<>();
    }

    /**
     * 根据厂房名称获取工段列表
     * 
     * @param factoryName 厂房名称
     * @return 工段列表
     */
    public List<WorkshopSection> getSectionsByFactoryName(String factoryName) {
        for (WorkshopArea area : areas) {
            for (WorkshopFactory factory : area.getFactories()) {
                if (factoryName.equals(factory.getFactoryName())) {
                    return factory.getSections();
                }
            }
        }
        return new ArrayList<>();
    }

    /**
     * 根据工段名称获取该工段下所有槽位信息
     * 
     * @param sectionName 工段名称
     * @return 该工段下的所有槽位DTO对象列表
     */
    public List<WorkshopSlotDTO> getSlotsBySection(String sectionName) {
        try {
            String cacheKey = WORKSHOP_SECTION_STATUS_KEY + sectionName;
            Map<String, Object> slotMap = redisCache.getCacheMap(cacheKey);
            
            if (slotMap == null || slotMap.isEmpty()) {
                log.debug("工段 {} 的槽位缓存为空", sectionName);
                return new ArrayList<>();
            }
            
            List<WorkshopSlotDTO> slotList = new ArrayList<>();
            for (Object value : slotMap.values()) {
                if (value instanceof WorkshopSlotDTO) {
                    slotList.add((WorkshopSlotDTO) value);
                }
            }
            // 按槽号排序
            slotList.sort((s1, s2) -> Integer.compare(s1.getSlotNumber(), s2.getSlotNumber()));
            
            // 使用 trace 级别，避免频繁的定时刷新导致日志过多
            log.trace("获取工段 {} 的槽位信息，共 {} 个槽位", sectionName, slotList.size());
            return slotList;
            
        } catch (Exception e) {
            log.error("获取工段 {} 槽位信息时发生错误", sectionName, e);
            return new ArrayList<>();
        }
    }


    /**
     * 缓存所有工段槽位信息到Redis
     * 使用Hash结构：大Key为WorkshopSlot，小Key为槽号，Value为WorkshopSlotDTO对象
     * 同时初始化每个工段的缓存 WORKSHOP_SECTION_STATUS_KEY + sectionName
     */
    private void cacheAllSlotsToRedis() {
        try {
            log.info("开始缓存所有工段槽位信息到Redis");
            
            // 清空现有缓存
            redisCache.deleteObject(WORKSHOP_SLOT_STATUS_KEY);
            
            int totalSlots = 0;
            
            // 遍历所有工区
            for (WorkshopArea area : areas) {
                // 遍历工区下的所有厂房
                for (WorkshopFactory factory : area.getFactories()) {
                    // 遍历厂房下的所有工段
                    for (WorkshopSection section : factory.getSections()) {
                        // 获取工段的槽位状态
                        List<WorkshopSlotInfo> slotInfos = section.getSlotInfos();
                        
                        // 工段级别的缓存Key
                        String sectionCacheKey = WORKSHOP_SECTION_STATUS_KEY + section.getSectionName();
                        
                        // 清空该工段的现有缓存
                        redisCache.deleteObject(sectionCacheKey);
                        
                        // 将每个槽位转换为DTO并缓存
                        for (WorkshopSlotInfo slotInfo : slotInfos) {
                            WorkshopSlotDTO slotDTO = new WorkshopSlotDTO(
                                slotInfo, 
                                section.getSectionName(), 
                                factory.getFactoryName(), 
                                area.getAreaName()
                            );
                            
                            // 使用槽号作为小Key存储到Redis Hash（全局缓存）
                            String slotKey = String.valueOf(slotInfo.getSlotNumber());
                            redisCache.setCacheMapValue(WORKSHOP_SLOT_STATUS_KEY, slotKey, slotDTO);
                            
                            // 同时缓存到工段级别的缓存中
                            redisCache.setCacheMapValue(sectionCacheKey, slotKey, slotDTO);
                            
                            totalSlots++;
                        }
                        
                        // 设置工段缓存过期时间（3600秒 = 1小时）
                        redisCache.expire(sectionCacheKey, 3600);
                        
                        log.debug("初始化工段 {} 的缓存，包含 {} 个槽位", section.getSectionName(), slotInfos.size());
                    }
                }
            }
            
            log.info("成功缓存 {} 个槽位信息到Redis，并初始化了所有工段的缓存", totalSlots);
            
        } catch (Exception e) {
            log.error("缓存槽位信息到Redis时发生错误", e);
        }
    }

    /**
     * 根据槽号从Redis获取槽位信息
     * 
     * @param slotNumber 槽号
     * @return WorkshopSlotDTO对象，如果不存在返回null
     */
    public WorkshopSlotDTO getSlotFromCache(Integer slotNumber) {
        try {
            return redisCache.getCacheMapValue(WORKSHOP_SLOT_STATUS_KEY, String.valueOf(slotNumber));
        } catch (Exception e) {
            log.error("从Redis获取槽位 {} 信息时发生错误", slotNumber, e);
            return null;
        }
    }

    /**
     * 获取所有缓存的槽位信息
     * 
     * @return 所有槽位的DTO对象列表
     */
    public List<WorkshopSlotDTO> getAllCachedSlots() {
        try {
            Map<String, Object> slotMap = redisCache.getCacheMap(WORKSHOP_SLOT_STATUS_KEY);
            if (slotMap == null || slotMap.isEmpty()) {
                return new ArrayList<>();
            }
            
            List<WorkshopSlotDTO> slotList = new ArrayList<>();
            for (Object value : slotMap.values()) {
                if (value instanceof WorkshopSlotDTO) {
                    slotList.add((WorkshopSlotDTO) value);
                }
            }
            
            return slotList;
        } catch (Exception e) {
            log.error("获取所有缓存槽位信息时发生错误", e);
            return new ArrayList<>();
        }
    }

    @Override
    public void onStatusUpdate(Device device, List<SlotStatus> slotStatusList) {
        try {
            for (SlotStatus slotStatus : slotStatusList) {
                WorkshopSlotDTO slotIDto = getSlotFromCache(slotStatus.getBusinessSlotNo());
                String sectionName = slotIDto.getSectionName();

                //需要将slotStatus状态信息保存到slotIDto中
                slotIDto.setPowerBoxDoorOpen(slotStatus.getDoorPowerBoxOpen());
                slotIDto.setControllerDoorOpen(slotStatus.getDoorControllerOpen());
                
                // 更新点位信息
                List<WorkshopPositionInfo> pointInfos = slotIDto.getPointInfos();
                if (pointInfos != null) {
                    for (WorkshopPositionInfo pointInfo : pointInfos) {
                        int pointNumber = pointInfo.getPointNumber();
                        switch (pointNumber) {
                            case 1:
                                pointInfo.setDischargeStatus(slotStatus.getDischarge1());
                                pointInfo.setJamStatus(slotStatus.getJam1());
                                break;
                            case 2:
                                pointInfo.setDischargeStatus(slotStatus.getDischarge2());
                                pointInfo.setJamStatus(slotStatus.getJam2());
                                break;
                            case 3:
                                pointInfo.setDischargeStatus(slotStatus.getDischarge3());
                                pointInfo.setJamStatus(slotStatus.getJam3());
                                break;
                            case 4:
                                pointInfo.setDischargeStatus(slotStatus.getDischarge4());
                                pointInfo.setJamStatus(slotStatus.getJam4());
                                break;
                            case 5:
                                pointInfo.setDischargeStatus(slotStatus.getDischarge5());
                                pointInfo.setJamStatus(slotStatus.getJam5());
                                break;
                            case 6:
                                pointInfo.setDischargeStatus(slotStatus.getDischarge6());
                                pointInfo.setJamStatus(slotStatus.getJam6());
                                break;
                        }
                    }
                }
                
                redisCache.setCacheMapValue(WORKSHOP_SECTION_STATUS_KEY + sectionName, 
                        String.valueOf(slotStatus.getBusinessSlotNo()),
                        slotIDto);
                //redisCache.expire(WORKSHOP_SECTION_STATUS_KEY + sectionName, 3600);

                //同步更新WORKSHOP_SLOT_CACHE_KEY
                redisCache.setCacheMapValue(WORKSHOP_SLOT_STATUS_KEY, 
                        String.valueOf(slotStatus.getBusinessSlotNo()), slotIDto);
            }
            
        } catch (Exception e) {
            log.error("处理设备 {} 状态更新时发生错误", device.getDeviceRelayCode(), e);
        }
    }

    /**
     * 获取缓存统计信息
     * 
     * @return 缓存统计信息字符串
     */
    public String getCacheStatistics() {
        try {
            Map<String, Object> slotMap = redisCache.getCacheMap(WORKSHOP_SLOT_STATUS_KEY);
            if (slotMap == null) {
                return "缓存为空";
            }
            
            int totalSlots = slotMap.size();
            int errorSlots = 0;
            int dischargePoints = 0;
            int jamPoints = 0;
            
            for (Object value : slotMap.values()) {
                if (value instanceof WorkshopSlotDTO) {
                    WorkshopSlotDTO slot = (WorkshopSlotDTO) value;
                    if (slot.hasError()) {
                        errorSlots++;
                    }
                    dischargePoints += slot.getDischargePointCount();
                    jamPoints += slot.getJamPointCount();
                }
            }
            
            return String.format("总槽数: %d, 异常槽数: %d, 下料点位: %d, 卡堵点位: %d", 
                    totalSlots, errorSlots, dischargePoints, jamPoints);
        } catch (Exception e) {
            log.error("获取缓存统计信息时发生错误", e);
            return "获取统计信息失败";
        }
    }
}
